package FWK.core;

import java.util.HashMap;
import java.util.Map;

import javax.swing.JFrame;
import javax.swing.SwingWorker;

import org.apache.log4j.Logger;

import FWK.exception.FwkValidationException;
import FWK.util.ActionType;
import FWK.util.FwkViewFactory;

public abstract class FwkController {

	private static Logger logger = Logger.getLogger(FwkController.class);

	protected FwkInternalView view;
	protected FwkInternalView viewAnterior;
	private JFrame container;
	
	public void setView(FwkInternalView view, JFrame containter) {
		this.view = view;
//		this.view.addController(this);
		this.container = containter;
		inicialize();
	}

	public void serViewAnt(FwkInternalView view) {
		this.viewAnterior = view;
	}

	private void redirect(FwkModelAndView mv) {
		logger.debug("se redirecciona desde la vista" + view.getClass().toString() + " a la vista "+ mv.getView() + " parametros " + mv.getParameters());
		
		FwkViewFactory.showInternalWindow(mv.getView(), view, container, mv.getParameters());
	}

	public void excecute(ActionType action, Map<String, Object> request, FwkInternalView caller) throws Exception {
		excecute(null, action, request, caller);
	}

	public void excecute(FwkForm form, ActionType action, FwkInternalView caller) throws Exception {
		excecute(form, action, null, caller);
	}

	public void excecute(final FwkForm form, final ActionType action, final Map<String, Object> request,
			final FwkInternalView caller) {
		logger.debug("llamado desde: " + caller.getClass().getName());
		logger.debug("ejecutando el controller: " + this.getClass());
		SwingWorker<FwkModelAndView, Object> t = new SwingWorker<FwkModelAndView, Object>() {

			FwkModelAndView mv = null;

			@Override
			protected FwkModelAndView doInBackground() {
				view.standBy();
				try {
					if (form != null) {
						form.validate();
					}
					logger.debug("request del controller" + request);
					mv = excecute(form, action, request);
				} catch (FwkValidationException e) {
					FwkErrorMannager.error(e, e.getMessage(), view);
				} catch (Exception e) {
					view.driveException(e);
				}
				return mv;
			}

			@Override
			protected void done() {
				if (!ActionType.VOLVER.equals(action)) {
					try {
						if (mv != null) {
							if (mv.getView() == null || mv.getView().equals(caller.getClass())) {
								view.update(mv.getParameters());
							} else {
								view.setVisible(false);
								redirect(mv);
							}
							logger.debug("response del controller: " + mv.getParameters());
							if (view != null) {
								logger.debug("se updatea la vista: " + view.getClass());
							}
						}
					} catch (Exception e) {
						FwkErrorMannager.error(e, "Error inesperado", view);
					} finally {
						if (view != null)
							view.activate();
					}
				} else {
					Runnable vuelvo = new Runnable() {
						@Override
						public void run() {
							if (viewAnterior != null) {
								logger.info("volvemos a la ventana: " + viewAnterior.getClass());
								viewAnterior.setVisible(true);
								logger.debug("request para la ventana " + viewAnterior.getClass() + ": " + request);
								if (request != null) {
									viewAnterior.update(request);
								} else {
									Map<String, Object> response = new HashMap<String, Object>();
									response.put(ActionType.VOLVER.toString(), action);
									viewAnterior.update(response);
								}
							} else {
								logger.info("toco volver pero es la primera ventana");
							}
						}
					};
					Thread t = new Thread(vuelvo);
					t.start();
				}
				logger.debug("finalizo el controller: " + FwkController.this.getClass());
			}
		};
		synchronized (t) {
			t.execute();
		}
	}

	private void inicialize() {
		Map<String, ? extends Object> parameters = getIniParameters();
		if (parameters != null) {
			view.initialize(parameters);
		}
	}

	protected Map<String, ? extends Object> getIniParameters() {
		return null;
	}

	protected abstract FwkModelAndView excecute(FwkForm form, ActionType action, Map<String, ?> request)
			throws Exception;

	public void close() {
		view = null;
	}
}
